module share.streambf;

import std.c.string : memcpy, memmove, memset;

struct StreamBuffer(T)
{
    private T[] m_pBuf = null;
    private int m_nBufLen = 0;
    private int m_nUseLen = 0;


    public ~this()
    {
        ClearAll();
    }
    
    public void ClearAll()
    {
        if ( m_pBuf !is null )
        {
            //free( m_pBuf );
            m_pBuf.length = 0;
            m_pBuf = null;
            m_nBufLen = 0;
            m_nUseLen = 0;
        }
    }
    
    public bool Expand( int nBufLen )
    {
        //m_pBuf = (T *) realloc( m_pBuf, sizeof( T ) * (m_nBufLen + nBufLen) );
        m_pBuf.length = m_nBufLen + nBufLen;
        if ( m_pBuf.length == 0 && (m_nBufLen + nBufLen) > 0 )
            return false;
        
        m_nBufLen += nBufLen;
        
        return true;
    }

    public bool Append( T[] buffer, int buflen )
    {
        if ( m_nBufLen < m_nUseLen + buflen )
        {
            if ( Expand( m_nUseLen + buflen - m_nBufLen ) == false )
                return false;
        }
        
        memcpy( m_pBuf.ptr + m_nUseLen, buffer.ptr, buflen );
        //m_pBuf[m_nUseLen .. m_nUseLen + buflen] = buffer;
        m_nUseLen += buflen;
        
        return true;
    }

    public void Remove( int buflen )
    {
        //int move_size = (m_nUseLen - buflen);
        //m_pBuf[0 .. move_size] = m_pBuf[buflen .. buflen + move_size];
        memmove( m_pBuf.ptr, m_pBuf.ptr + buflen, T.sizeof * (m_nUseLen - buflen) );
        
        Expand( -buflen );
        
        m_nUseLen -= buflen;
    }

    @property public T[] buffer() { return m_pBuf; }
    @property public int size() { return m_nUseLen; }
    @property public T opIndex(int index) { return m_pBuf[ index ]; }
    
    //operator T * ()             { return m_pBuf; }
    //operator const T * () const { return (const T *) m_pBuf; }
}